/**
 * 
 * 
 *  
 *====================================================
 * 文件名称: MyFormBeanConfig.java
 * 修订记录：
 * No    日期				作者(操作:具体内容)
 *====================================================
 * 类描述：(说明未实现或其它不应生成javadoc的内容)
 * 
 */
package com.devframe.web.struts1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.FormBeanConfig;

import com.devframe.web.loader.MyWebContextLoader;


/**
 * <pre>
 * &lt;b&gt;&lt;font color=&quot;blue&quot;&gt;MyFormBeanConfig&lt;/font&gt;&lt;/b&gt;
 * </pre>
 * 
 * <pre>
 * &lt;b&gt; --描述说明--&lt;/b&gt;
 * </pre>
 * <pre></pre>
 * <pre>
 * &lt;b&gt;--样例--&lt;/b&gt;
 *   MyFormBeanConfig obj = new MyFormBeanConfig();
 *   obj.method();
 * </pre>
 * 
 * JDK版本：JDK1.4
 * 
 */
public class MyFormBeanConfig extends FormBeanConfig {
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -461721342256464384L;

    private static Logger logger = Logger.getLogger(MyFormBeanConfig.class);

    /**
     * 替换struts默认的actionForm创建类 处理了actionForm中对象类型属性，自动创建，避免bean not
     * specified的错误。
     * 
     * @param servlet
     *            The action servlet
     * @return ActionForm instance
     * @throws IllegalAccessException
     *             if the Class or the appropriate constructor is not accessible
     * @throws InstantiationException
     *             if this Class represents an abstract class, an array class, a
     *             primitive type, or void; or if instantiation fails for some
     *             other reason
     * @Override
     */
    public ActionForm createActionForm(ActionServlet servlet) throws IllegalAccessException,
        InstantiationException {
        ActionForm form = super.createActionForm(servlet);
        if(form!=null){
            autoCreateNullProps(form,false);
        }
        return form;
    }

    /**
     * autoCreateNullProps
     * 
     * @param obj obj
     * @throws IllegalAccessException
     *             if the Class or the appropriate constructor is not accessible
     * @throws InstantiationException
     *             if this Class represents an abstract class, an array class, a
     *             primitive type, or void; or if instantiation fails for some
     *             other reason
     * 
     */
    private void autoCreateNullProps(Object obj,boolean nested) throws IllegalAccessException, InstantiationException {
        //TODO 可以针对没给ActionForm类需要进行预处理的属性进行缓存，以提高效率。
        
        // 开始处理非基本类型的属性，用默认的构造函数创建实例。
        //Method[] methods = obj.getClass().getDeclaredMethods();
        //获取包名的前缀
    	String packagePrefix=MyWebContextLoader.getInstance().getPackageNamePrefix();
        
        Method[] methods = obj.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            //只对自定义的类的属性进行处理
            Class declareClass = method.getDeclaringClass();
            if(declareClass.getName().indexOf(packagePrefix)<0){
                continue;
            }
            //对单参数的set方法进行处理
            if (method.getModifiers() == Modifier.PUBLIC && method.getName().indexOf("set") == 0
                && method.getParameterTypes().length == 1) {
                String fieldName = method.getName().substring(3);
                fieldName = StringUtils.uncapitalize(fieldName);
                Object fieldValue = null;
                Class<?> type = method.getParameterTypes()[0];
                //logger.info(fieldName + ":" + type.getName());
                // 不是简单类型，也不是数组，也不是接口则进行处理
                if (!type.isPrimitive() && !type.isArray() && !type.isInterface()  && type.getPackage().getName().indexOf(packagePrefix) == 0 ) {//
                    fieldValue = getFieldValue(obj, methods, fieldName);
                    if (fieldValue != null) {
                        continue;
                    } else {
                        fieldValue = type.newInstance();
                        if(!nested) autoCreateNullProps(fieldValue,true);
                    }
                } else if (type.isAssignableFrom(Set.class) && !nested) {
                    // Class compentType = type.getComponentType();
                    fieldValue = getFieldValue(obj, methods, fieldName);
                    if (fieldValue != null) {
                        continue;
                    } else {
                        fieldValue = new HashSet();
                    }
                }else if (type.isAssignableFrom(List.class) && !nested) {
                    // Class compentType = type.getComponentType();
                    fieldValue = getFieldValue(obj, methods, fieldName);
                    if (fieldValue != null) {
                        continue;
                    } else {
                        fieldValue = new ArrayList();
                    }
                } else if (type.isAssignableFrom(Map.class) && !nested) {
                    fieldValue = getFieldValue(obj, methods, fieldName);
                    if (fieldValue != null) {
                        continue;
                    } else {
                        fieldValue = new HashMap();
                    }
                } else {
                    continue;
                }
                try {
                    //logger.info("auto init "+fieldName +":" + type.getName());
                    method.invoke(obj, new Object[] { fieldValue });
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        //logger.info("autoCreateNullProps end "+obj);
        
    }

    /**
     * getFieldValue
     * @param form form
     * @param methods methods
     * @param fieldName fieldName
     * @return 属性原始值
     * 
     */
    private Object getFieldValue(Object form, Method[] methods, String fieldName) {
        Method getter = null;
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            if (method.getName().equals("get" + StringUtils.capitalize(fieldName))) {
                getter = method;
            }
        }
        if (getter != null) {
            try {
                return getter.invoke(form);
            } catch (Exception e) {
                logger.info(getter.getName());
                e.printStackTrace();
            }
        }
        return null;
    }

}
